/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package io.simple.core.handlers;

/**
 *
 * @author rehak
 */
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import com.google.protobuf.Message;
import injections.annotations.Property;
import io.simple.core.RequestContext;
import io.simple.core.chain.RequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;

/**
 * @author Tom
 */
public abstract class GPBJSONIncomingHandler<IN extends Message> implements RequestHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GPBJSONIncomingHandler.class);
    private AtomicLong decodeException = new AtomicLong(0);
    private AtomicLong processException = new AtomicLong(0);
    private IN inProto;
    @Property
    private String pattern;
    @Property(optional = true)
    private int patternFlags = 0;

    public GPBJSONIncomingHandler() {
        Class<? extends GPBJSONIncomingHandler> aClass = this.getClass();
        ParameterizedType genericSuperclass = (ParameterizedType) aClass.getGenericSuperclass();
        Type[] args = genericSuperclass.getActualTypeArguments();
        Class inCls = (Class) args[0];
        init(inCls);

    }

    public GPBJSONIncomingHandler(Class<? extends Message> inCls) {
        init(inCls);
    }

    private void init(Class inCls) {
        try {
            inProto = (IN) inCls.getMethod("getDefaultInstance").invoke(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ByteBuffer processRequest(RequestContext context, ByteBuffer data) throws Exception {
        IN decode;
        ByteBuffer outBuf;
        try {
            decode = MessageDecoder.decode(inProto, data, context);
        } catch (Exception e) {
            LOGGER.error("Exception decoding message", e);
            decodeException.incrementAndGet();
            throw e;
        }
        try {
            outBuf = process(context, decode);
        } catch (Exception e) {
            LOGGER.error("Exception encoding response", e);
            processException.incrementAndGet();
            throw e;
        }
        return outBuf;
    }

    @Override
    public Pattern getPath() {
        if (patternFlags == 0) {
            return Pattern.compile(pattern);
        } else {
            return Pattern.compile(pattern, patternFlags);
        }
    }
    public abstract ByteBuffer process(RequestContext context, IN data) throws Exception;
}
